/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain an copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ee.ioc.phon.ohos.speechutils.abilityslice;

import com.google.gson.Gson;

import ee.ioc.phon.ohos.speechutils.utils.Define;
import ee.ioc.phon.ohos.speechutils.utils.LogUtils;
import ee.ioc.phon.ohos.speechutils.utils.ResultInfo;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.ai.asr.AsrClient;
import ohos.ai.asr.AsrIntent;
import ohos.ai.asr.AsrListener;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.audio.AudioCapturer;
import ohos.media.audio.AudioCapturerInfo;
import ohos.media.audio.AudioStreamInfo;
import ohos.utils.PacMap;

/**
 * 语音转文字功能类
 *
 * @since 2021-03-20
 */
public abstract class AsrBaseAbilitySlice extends AbilitySlice implements RmsChangedInterface, ShowAsrResult {
    private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "AsrAbilitySlice");
    private AsrClient asrClient = null;
    private AudioCapturer mAudioCapturer = null;
    private AsrIntent initIntent = null;
    private boolean isFlag = false;
    private AsrListener mMyAsrListener = new AsrListener() {
        @Override
        public void onInit(PacMap pacMap) {
            HiLog.info(LABEL_LOG, "onInit");
        }

        @Override
        public void onBeginningOfSpeech() {
            HiLog.info(LABEL_LOG, "onBeginningOfSpeech");
        }

        @Override
        public void onRmsChanged(float energyV) {
            rmsChanged(energyV);
        }

        @Override
        public void onBufferReceived(byte[] bytes) {
            HiLog.info(LABEL_LOG, "onBufferReceived");
        }

        @Override
        public void onEndOfSpeech() {
            HiLog.info(LABEL_LOG, "onEndOfSpeech");
        }

        @Override
        public void onError(int id) {
            HiLog.info(LABEL_LOG, "onError = " + id);
        }

        @Override
        public void onResults(PacMap pacMap) {
        }

        @Override
        public void onIntermediateResults(PacMap pacMap) {
            results2(pacMap);
            HiLog.info(LABEL_LOG, "onIntermediateResults");
        }

        @Override
        public void onEnd() {
            HiLog.info(LABEL_LOG, "onEnd");
        }

        @Override
        public void onEvent(int evenCode, PacMap pacMap) {
            HiLog.info(LABEL_LOG, "onEvent");
        }

        @Override
        public void onAudioStart() {
        }

        @Override
        public void onAudioEnd() {
            HiLog.info(LABEL_LOG, "onAudioEnd");
        }
    };

    private EventHandler handler = new EventHandler(EventRunner.create());
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while (isFlag) {
                byte[] buffer = new byte[Define.BYTE_BUFFER];
                /**
                 * 对于长度大于1280的音频，需要多次调用writePcm分段传输
                 */
                mAudioCapturer.read(buffer, 0, buffer.length);
                asrClient.writePcm(buffer, buffer.length);
                try {
                    Thread.sleep(Define.SLEEP_INTERVAL);
                } catch (InterruptedException e) {
                    LogUtils.log(LogUtils.DEBUG, "test", e.getMessage());
                }
            }
        }
    };

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(setLayout());
        initView();
        initAsrClient();
    }

    /**
     * 初始化asrClient
     */
    private void initAsrClient() {
        initAudioStream();
        asrClient = AsrClient.createAsrClient(this).orElse(null);
        initIntent = new AsrIntent();
        initIntent.setVadFrontWaitMs(Define.YIQIAN);
        initIntent.setVadEndWaitMs(Define.YIQIAN);
        initIntent.setAudioSourceType(AsrIntent.AsrAudioSrcType.ASR_SRC_TYPE_PCM);
        asrClient.init(initIntent, mMyAsrListener);
    }

    /**
     * 初始化录音
     */
    private void initAudioStream() {
        AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder()
                .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT)
                .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO)
                .sampleRate(Define.SAMPLE_RATE) // 采样率
                .build();
        AudioCapturerInfo audioCapturerInfo = new AudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo)
                .build();
        mAudioCapturer = new AudioCapturer(audioCapturerInfo);
    }

    /**
     * 停止监听
     */
    protected void stopRecoding() {
        isFlag = false;
        handler.removeTask(runnable);
        mAudioCapturer.stop();
        asrClient.stopListening();
        asrClient.cancel();
        HiLog.info(LABEL_LOG, "stopListen");
    }

    /**
     * 开始监听
     */
    protected void startRecoding() {
        HiLog.info(LABEL_LOG, "startListen");
        asrClient.startListening(initIntent);
        mAudioCapturer.start();
        isFlag = true;
        handler.postTask(runnable);
    }

    /**
     * 能力变化
     *
     * @param energyV 能量值
     */
    private void rmsChanged(float energyV) {
        HiLog.info(LABEL_LOG, "onRmsChanged = " + energyV);
        getUITaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                int asd = 1;
                float energy = energyV;
                if (energy > Define.ENERGYYIQN) {
                    asd = (int) (energy / Define.ENERGSIQIAN);
                } else {
                    asd = (int) (energy / Define.ENERGSANSHI);
                }
                if (asd < 1) {
                    asd = 1;
                }
                showRmsChanged(asd);
                HiLog.info(LABEL_LOG, "energy = " + asd);
            }
        }, 0);
    }

    /**
     * 识别结果
     *
     * @param pacMap 数据
     */
    private void results(PacMap pacMap) {
        HiLog.info(LABEL_LOG, "onResults");
        asrClient.stopListening(); // 停止识别
        asrClient.cancel(); // 取消识别
        Gson gson = new Gson();
        ResultInfo resultInfo = gson.fromJson(pacMap.getString("results_recognition"), ResultInfo.class);
        if (resultInfo != null) {
            getUITaskDispatcher().delayDispatch(new Runnable() {
                @Override
                public void run() {
                    showAsrResult(resultInfo.getResult().get(0).getWord());
                }
            }, 0);
        }
    }

    /**
     * 片段识别
     *
     * @param pacMap 数据
     */
    protected void results2(PacMap pacMap) {
        HiLog.info(LABEL_LOG, "onResults");
        Gson gson = new Gson();
        ResultInfo resultInfo = gson.fromJson(pacMap.getString("results_partial"), ResultInfo.class);
        if (resultInfo != null) {
            getUITaskDispatcher().delayDispatch(new Runnable() {
                @Override
                public void run() {
                    showAsrResult(resultInfo.getResult().get(0).getWord());
                }
            }, 0);
        }
    }

    /**
     * 布局
     *
     * @return 布局id
     */
    public abstract int setLayout();

    /**
     * 布局
     */
    public abstract void initView();

    @Override
    protected void onStop() {
        super.onStop();
        asrClient.destroy();
    }
}
